#region Imported Namespaces
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;

using PHSRAG.Insight21.SearchContext;
using Calendar = PHSRAG.WebControls.Calendar;
using DataAccess = PHSRAG.Utility.DataAccess;
using SessionCachePolicy = PHSRAG.Insight21.Policy.SessionCachePolicy;
using PHSRAG.Insight21.InsightUtilities;
using Policy = PHSRAG.Insight21.Policy;
using UserContext = PHSRAG.Insight21.Context.UserContext;
using PHSRAG.Insight21.CDS;
#endregion

namespace PHSRAG.Insight21.InsightWebControls
{
    /// <summary>
    /// The AnimalsSearch control is used by Animals summary pages.
    /// </summary>
    [ToolboxData("<{0}:AnimalsSearch runat=server />"), Designer(typeof(AnimalsSearchDesigner))]
    public class AnimalsSearch : BaseSearch, INamingContainer, ISearch
    {
        #region Constants
        private const string calendarDefaultPrompt = "--Select--";
        private const int defaultSelectedIndex = -1;//None selected by default
        #endregion

        #region Instance Variables
        private Policy.ICachePolicy cachePolicy;
        private TextBox sponsorName;
        //private TextBox version;
        private Calendar expirationStartDate;
        private Calendar expirationEndDate;
        private DropDownList speciesName;
        private CheckBox radioIsotope;
        private CheckBox biologicalAgent;
        private CheckBox toxicChemical;
        private CheckBox tissueTest;
        private ControlCollection controlCollection;
        #endregion

        #region ISearch Members
        /// <summary>
        /// Reset the internal search state. This involves setting the value for all controls 
        /// to their default values and resetting the cached state of the search context.
        /// </summary>		
        public void Reset()
        {
            ResetControls(controlCollection);

            expirationStartDate.Reset();
            expirationEndDate.Reset();
            expirationStartDate.Prompt = calendarDefaultPrompt;
            expirationEndDate.Prompt = calendarDefaultPrompt;

            AnimalsSearchContext searchContext = cachePolicy.GetCachedObject(AnimalsSearchContext.CacheKey) as AnimalsSearchContext;
            if (searchContext != null)
                searchContext.Reset(Page.Request.Url.ToString());
        }

        /// <summary>
        /// Get the search criteria from the common search context.
        /// </summary>
        public SearchCriteria SearchCriteria
        {
            get
            {
                return ((AnimalsSearchContext)cachePolicy.GetCachedObject(AnimalsSearchContext.CacheKey)).GetSearchCriteria(Page.Request.Url.ToString());
            }
        }


        /// <summary>
        /// Get the search criteria from what's rendered into the search context's search criteria.
        /// This is done by collecting the current values in all controls, 
        /// storing them in the AnimalsSearchContext, and then returning the search criteria.  We only 
        /// need to update the criterian for non-textbox controls b/c the Common search handles them
        /// </summary>
        public SearchCriteria UpdateSearchCriteria()
        {
            UserContext userContext = (UserContext)cachePolicy.GetCachedObject(UserContext.CacheKey);
            return GetSearchCriteria(userContext.DomainUserId, controlCollection);
        }

        #endregion

        #region Private Properties
        /// <summary>
        /// Determine if the control is in design mode. It is if there is not HTTP context.
        /// </summary>
        private static bool IsDesignMode
        {
            get { return HttpContext.Current == null; }
        }
        #endregion

        #region Internal Methods
        /// <summary>
        /// This method is ONLY invoked by the associated designer to show the control contents at design time.
        /// </summary>
        internal void Design()
        {
            EnsureChildControls();
        }
        #endregion

        #region Overrides

        /// <summary>
        /// Create all controls. Notice that the creation is more than just instantiating the controls. 
        /// It also involves generating the underlying HTML so that the controls shows up per the need.
        /// </summary>
        protected override void CreateChildControls()
        {
            CreateControls();
            GenerateControlTree();
        }

        /// <summary>
        /// Initializes the cachepolicy. Create and cache a AnimalsearchContext object if necessary.
        /// Note that controls whose state must persist in the view state MUST be created BEFORE OnInit completes. We do
        /// this simply by invoking EnsureChildControls().
        /// </summary>
        /// <param name="e">Argument associated with the event</param>
        protected override void OnInit(EventArgs e)
        {
            cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];
            AnimalsSearchContext searchContext = cachePolicy.GetCachedObject(AnimalsSearchContext.CacheKey) as AnimalsSearchContext;
            if (searchContext == null)
            {
                searchContext = new AnimalsSearchContext(cachePolicy);
            }

            EnsureChildControls();
            base.OnInit(e);
            searchContext.GetSearchCriteria(Page.Request.Url.ToString(), controlCollection);
        }

        /// <summary>
        /// Initialize the contents of all controls on first load. If the AnimalsSearchContext is not cached yet, a
        /// new instance is created and cached.
        /// </summary>
        /// <param name="e">Argument associated with the event</param>
        protected override void OnLoad(EventArgs e)
        {
            cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];

            if (!Page.IsPostBack)
            {
                EnsureChildControls();
                LoadDropdownList(speciesName, GetAnimalSpecies(),defaultSelectedIndex);
                AnimalsSearchContext searchContext = cachePolicy.GetCachedObject(AnimalsSearchContext.CacheKey) as AnimalsSearchContext;
                if (searchContext == null)
                {
                    searchContext = new AnimalsSearchContext(cachePolicy);
                    searchContext.Load(DataAccess.ConnectionString);
                    searchContext.Cache();
                }

				SetControlState(searchContext.GetSearchCriteria(Page.Request.Url.ToString(), controlCollection));
            }
        }

        /// <summary>
        /// Set the state for all constituent controls, and register a client script block for the express purpose of
        /// validating the date ranges of all paired Calendar controls in this search block.
        /// </summary>
        /// <param name="e">Argument associated with the event</param>
        /// <remarks>
        /// <protocolId>Why are the actions taken in this method not being done on control load?</protocolId>
        /// <protocolId>During the non-postback construction of the control, the OnLoad method is invoked BEFORE the
        /// CreateChildControls method. The actual creation of constitutent controls are done within the context of
        /// the CreateChildControls methos. Setting the state of control relies on (obviously) the fact that the controls
        /// have been created. So, setting the state in OnLoad for the non-postback condition would fail.</protocolId>
        /// <protocolId>Interestingly, the sequence of method invocations reverses on postback: CreateChildControls is invoked
        /// before OnLoad.</protocolId>
        /// </remarks>
        protected override void OnPreRender(EventArgs e)
        {
            if (!IsDesignMode)
            {
                if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(),Constants.ValidateDateRangeScriptKey))
                {
                    string script = string.Format(
                        "<script language=\"javascript\">\n" +
                        "function ValidateDateRange()\n" +
                        "{{\n" +
                        "\tif (document.getElementById(\"{0}\") != null)\n" +
                        "\t\tvar expirationStartText = document.getElementById(\"{0}\").value;\n" +
                        "\tif (document.getElementById(\"{1}\") != null)\n" +
                        "\t\tvar expirationEndText = document.getElementById(\"{1}\").value;\n" +
                        "\tif (expirationStartText != null && expirationStartText != \"\" && expirationEndText != null && expirationEndText != \"\")\n" +
                        "\t{{\n" +
                        "\t\tvar expirationStartDate = new Date(expirationStartText);\n" +
                        "\t\tvar expirationEndDate = new Date(expirationEndText);\n" +
                        "\t\tif (expirationStartDate > expirationEndDate)\n" +
                        "\t\t{{\n" +
                        "\t\t\talert('Expiration Start Date cannot be after Expiration End Date.');\n" +
                        "\t\t\tdocument.getElementById(\"{1}\").focus();\n" +
                        "\t\t\treturn false;\n" +
                        "\t\t}}\n" +
                        "\t\treturn true;\n" +
                        "\t}}\n" +
                        "\treturn true;\n" +
                        "}}\n" +
                        "</script>\n",
                        (expirationStartDate == null) ? "" : expirationStartDate.SelectedDateClientId,
                        (expirationEndDate == null) ? "" : expirationEndDate.SelectedDateClientId);

                    Page.ClientScript.RegisterClientScriptBlock(GetType(),Constants.ValidateDateRangeScriptKey, script);
                }
            }

            base.OnPreRender(e);
        }

        /// <summary>
        /// Render the control. Note that we simply ensure that all child controls are created, 
        /// and then delegate the call back to the base class.
        /// </summary>
        /// <param name="writer">The writer to use for rendering</param>
        protected override void Render(HtmlTextWriter writer)
        {
            EnsureChildControls();
            base.Render(writer);
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Create all controls in the CommonSearch.
        /// </summary>
        private void CreateControls()
        {
            Controls.Clear();
            controlCollection = new ControlCollection(this);

            sponsorName = new TextBox();
            sponsorName.ID = "protocolSponsor";
            sponsorName.CssClass = "DataInput";
            sponsorName.Attributes["Label"] = "Sponsor Name";
            controlCollection.Add(sponsorName);

            expirationStartDate = new Calendar();
            expirationStartDate.ID = "expirationDateFrom";
            expirationStartDate.Attributes["Label"] = "Expiration Date From";
            controlCollection.Add(expirationStartDate);

            expirationEndDate = new Calendar();
            expirationEndDate.ID = "expirationDateTo";
            expirationEndDate.Attributes["Label"] = "Expiration Date To";
            controlCollection.Add(expirationEndDate);

            speciesName = new DropDownList();
            speciesName.ID = "speciesName";
            speciesName.CssClass = "DataInput";
            speciesName.AutoPostBack = false;
            speciesName.Attributes["Label"] = "Species";
            controlCollection.Add(speciesName);

            radioIsotope = new CheckBox();
            radioIsotope.ID = "radioIsotope";
            radioIsotope.Attributes["Label"] = "Radio Isotope";
            radioIsotope.CssClass = "DataInput";
            controlCollection.Add(radioIsotope);

            biologicalAgent = new CheckBox();
            biologicalAgent.ID = "biologicalAgent";
            biologicalAgent.Attributes["Label"] = "Biological Agent";
            biologicalAgent.CssClass = "DataInput";
            controlCollection.Add(biologicalAgent);

            toxicChemical = new CheckBox();
            toxicChemical.ID = "toxicChemicals";
            toxicChemical.Attributes["Label"] = "Toxic Chemicals";
            toxicChemical.CssClass = "DataInput";
            controlCollection.Add(toxicChemical);

            tissueTest = new CheckBox();
            tissueTest.ID = "tissueTest";
            tissueTest.Attributes["Label"] = "Tissue Test";            
            tissueTest.CssClass = "DataInput";
            controlCollection.Add(tissueTest);
            
        }

        /// <summary>
        /// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
        /// </summary>
        private void GenerateControlTree()
        {
            string searchClientId = ((Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey]).GetCachedObject(Constants.SearchButtonClientIDKey) as string;
            if (searchClientId == null)
                searchClientId = "expandingPanel_commonSearch_search";

            Table t1 = new Table();
            t1.CssClass = "Search";
            t1.CellSpacing = t1.CellPadding = 5;
            t1.Attributes.Add("onkeypress", "return ClickButton(event, '" + searchClientId + "')");
            Controls.Add(t1);

            TableRow t1r1 = new TableRow();
            t1.Rows.Add(t1r1);
            TableCell t1r1c1 = new TableCell();
            t1r1c1.Attributes["valign"] = "top";
            t1r1.Cells.Add(t1r1c1);
            t1r1c1.Controls.Add(GenerateControlTreeForLeftSection());

            TableCell t1r1c3 = new TableCell();
            t1r1c3.Attributes["valign"] = "top";
            t1r1.Cells.Add(t1r1c3);
            t1r1c3.Controls.Add(CreateControlTreeForRightSection());


        }

        /// <summary>
        /// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
        /// This is the left side of the search that contains the two text boxes 
        /// r1c1: Sponsor Name Label
        /// r1c2: Sponsor Name TextBox
        /// r2c1: Version Name/Number Label
        /// r2c2: Version Name/Number TextBox
        /// </summary>
        private Table GenerateControlTreeForLeftSection()
        {
            Table t = new Table();
            t.CssClass = "Search";
            t.CellSpacing = t.CellPadding = 5;
            TableRow r1 = new TableRow();
            t.Rows.Add(r1);

            TableCell r1c1 = new TableCell();
            r1c1.Attributes["align"] = "right";
            r1c1.Text = "<nobr>&nbsp;Sponsor&nbsp;Name:&nbsp;</nobr>";
            r1.Cells.Add(r1c1);

            TableCell r1c2 = new TableCell();
            r1c2.Attributes["align"] = "left";
            r1.Cells.Add(r1c2);
            r1c2.Controls.Add(sponsorName);

            TableRow r2 = new TableRow();
            t.Rows.Add(r2);

            TableCell r2c1 = new TableCell();
            r2c1.Attributes["align"] = "right";
            r2c1.Text = "Species";
            r2.Cells.Add(r2c1);

            TableCell r2c2 = new TableCell();
            r2c2.Attributes["align"] = "left";
            r2.Cells.Add(r2c2);
            r2c2.Controls.Add(speciesName);
            
            return t;
        }

        /// <summary>
        /// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
        /// This is the right side that contains the calendar control 
        /// r1c1: IRB expiration start date label for calendar control
        /// r1c2: IRB expiration start date calendar control 
        /// r1c3: IRB expiration end date label for calendar control 
        /// r1c4: IRB expiration end date calendar control

        /// </summary>
        private Table CreateControlTreeForRightSection()
        {
            Table t = new Table();
            t.CssClass = "Search";
            t.CellSpacing = t.CellPadding = 5;

            TableRow r1 = new TableRow();
            t.Rows.Add(r1);
            TableCell r1c1 = new TableCell();
            r1c1.Attributes["align"] = "right";
            r1c1.Text = "<nobr>&nbsp;IACUC&nbsp;Expiration&nbsp;Date&nbsp;Between:&nbsp;</nobr>";
            r1.Cells.Add(r1c1);

            TableCell r1c2 = new TableCell();
            r1c2.Attributes["align"] = "left";
            r1.Cells.Add(r1c2);
            r1c2.Controls.Add(IsDesignMode ? (Control)new LiteralControl(Calendar.DesignTimeHTML) : (Control)expirationStartDate);

            TableCell r1c3 = new TableCell();
            r1c3.Attributes["align"] = "right";
            r1c3.Text = "Radioisotope";
            r1.Cells.Add(r1c3);

            TableCell r1c4 = new TableCell();
            r1c4.Attributes["align"] = "left";
            r1.Cells.Add(r1c4);
            r1c4.Controls.Add(radioIsotope);

            TableCell r1c5 = new TableCell();
            r1c5.Attributes["align"] = "right";
            r1c5.Text = "Biological Agent";
            r1.Cells.Add(r1c5);

            TableCell r1c6 = new TableCell();
            r1c6.Attributes["align"] = "left";
            r1.Cells.Add(r1c6);
            r1c6.Controls.Add(biologicalAgent);

            TableRow r2 = new TableRow();
            t.Rows.Add(r2);

            TableCell r2c1 = new TableCell();
            r2c1.Attributes["align"] = "right";
            r2c1.Text = "And:&nbsp;";
            r2.Cells.Add(r2c1);

            TableCell r2c2 = new TableCell();
            r2c2.Attributes["align"] = "left";
            r2.Cells.Add(r2c2);
            r2c2.Controls.Add(IsDesignMode ? (Control)new LiteralControl(Calendar.DesignTimeHTML) : (Control)expirationEndDate);

            TableCell r2c3 = new TableCell();
            r2c3.Attributes["align"] = "right";
            r2c3.Text = "Toxic Chemicals";
            r2.Cells.Add(r2c3);

            TableCell r2c4 = new TableCell();
            r2c4.Attributes["align"] = "left";
            r2.Cells.Add(r2c4);
            r2c4.Controls.Add(toxicChemical);

            TableCell r2c5 = new TableCell();
            r2c5.Attributes["align"] = "right";
            r2c5.Text = "TissueTest";
            r2.Cells.Add(r2c5);

            TableCell r2c6 = new TableCell();
            r2c6.Attributes["align"] = "left";
            r2.Cells.Add(r2c6);
            r2c6.Controls.Add(tissueTest);
            
            return t;
        }

        /// <summary>
        /// Helper method to load a drop-down-list with data.
        /// </summary>
        /// <param name="list">drop-down-list to load</param>
        /// <param name="table">DataTable which contains data to load</param>
        /// <param name="valueColumnName">Name of the column which holds the value for the row</param>
        /// <param name="selectedIndex">Index of the dropdown which is defaulted to</param>
        private static void LoadDropdownList(DropDownList list, ArrayList speciesList, int selectedIndex)
        {

            list.Items.Add(new ListItem(PHSRAG.WebControls.Helper.SelectPrompt,"-1"));
            foreach (RefCode refCode in speciesList)
                list.Items.Add(new ListItem((string)refCode.Meaning, refCode.Code));
                     
            list.SelectedIndex = selectedIndex;
            list.Enabled = (list.Items.Count > 1);
        }

        private ArrayList GetAnimalSpecies()
        {
            CDS.RefCodes refCodes =
                (CDS.RefCodes)((Policy.ICachePolicy)Page.Application[Policy.Names.ApplicationCachePolicyKey]).GetCachedObject(CDS.RefCodes.CacheKey);

            ArrayList animalSpecies =
                (ArrayList)refCodes.GetRefCodes(Humans.Constants.AnimalSpecies.Domain);

            return animalSpecies;

        }
        #endregion
    }

    #region Class AnimalsSearchDesigner
    /// <summary>
    /// Designer associated with the AnimalsSearch control.
    /// </summary>
    /// <remarks>
    /// This class cannot be used directly.
    /// </remarks>
    public class AnimalsSearchDesigner : ControlDesigner
    {
        #region Overrides
        /// <summary>
        /// Force the control to create its child controls for display at design time.
        /// </summary>
        /// <returns>HTML representation of the control</returns>
        public override string GetDesignTimeHtml()
        {
            ((AnimalsSearch)Component).Design();
            return base.GetDesignTimeHtml();
        }
        #endregion
    }

    #endregion
}